//============================================================================
// Name        : URLNormalizer.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <vector>
#include <list>
#include "URLNormalizer.h"

using namespace std;

//DebugLogger dbug_normalize("dbug_normalize");

URLNormalizer::URLNormalizer() {
		defaultDirectoryIndexes.push_back("/index.html");
		defaultDirectoryIndexes.push_back("/index.jsp");	
		defaultDirectoryIndexes.push_back("/index.shtml");
		defaultDirectoryIndexes.push_back("/index.asp");
		defaultDirectoryIndexes.push_back("/index.aspx");
		defaultDirectoryIndexes.push_back("/index.php");
		defaultDirectoryIndexes.push_back("/index.htm");
		defaultDirectoryIndexes.push_back("/index.shm");
}


//Nao inclui a barra no final!!!
void URLNormalizer::removePath(string & normalizedUrl) {
	uint protocol = normalizedUrl.find("://");
	if (protocol != string::npos) {
		uint slash = normalizedUrl.find("/", protocol+3);
		normalizedUrl = normalizedUrl.substr(0, slash);
	}
}


//std::list<string> URLNormalizer::normalize(const std::list<string> originalURLList) {
//	std::list<string> normalizedList;
//	try{
//	std::list<string>::const_iterator it;
//	for ( it = originalURLList.begin() ; it != originalURLList.end(); it++ )
//	    normalizedList.push_back(normalize(*it));
//	}catch(...){
//		// cout << "Baggio estragando a brincadeira... " << endl;
//	}
//	return normalizedList;
//}

void URLNormalizer::normalize(string & normalizedURL) {

	try{
	//cout << "AAAAAAAA: " << originalURL << endl;
//	if (originalURL.size() <= 1){
//		URL url()
//	}
	string domain = "";
	string path = "";
	string protocol = "";
//	toLower(normalizedURL);
//	cout << "URL1: " << normalizedURL << endl;
	removeFragmentAndQuestionMark(normalizedURL);
	capitalizeEscapeSequences(normalizedURL);
//	cout << "URL2: " << normalizedURL << endl;
//	cout << "URL3: " << normalizedURL << endl;
	addTrailing(normalizedURL);
//	cout << "URL4: " << normalizedURL << endl;
	
	protocol = getProtocol(normalizedURL);
	uint slashIndex = normalizedURL.find("/");
	if (slashIndex != string::npos) {
		domain = normalizedURL.substr(0, slashIndex);
		path = normalizedURL.substr(slashIndex + 1, normalizedURL.size());
	}
	else {
//		cout << "ERROR: URL had no \"/\""<< endl;
	}
//	cout << "PATH1: " << path << endl;
	removeDefaultPort(domain);
	addTrailing(domain);
	if (path != "") {
		removeDirectoryIndexes(path);
		removeDotSegments(path);
//		cout << "PATH2: " << path << endl;
//		cout << "PATH3: " << path << endl;
		removeTrailing(path);
//		cout << "PATH4: " << path << endl;
	}
//	cout << "protocol: " << protocol << endl;
//	cout << "domain: " << domain << endl;
//	cout << "path: " << path << endl;
//	URL url(domain, path, protocol);
//	dbug_normalize.infoMsg(originalURL);
	normalizedURL = protocol+domain+path;
	trim(normalizedURL);
	}catch(...){
//		cout << "Mc mandou mal, link quebrado: " << originalURL << endl;
		
//		dbug_normalize.errorMsg(originalURL);
		
//		URL url_google("www.google.com/", "", "http://");
//		return url_google;
//		URL url_null(" ", "", "http://");
		normalizedURL = "http://";	
		
	}
}

void URLNormalizer::toLower(string & str) {
	try{
	for (uint i = 0; i < str.size(); i++)
		str[i] = tolower(str[i]);
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}

inline string URLNormalizer::getProtocol (string  & str) {
	try{
	uint index = str.find("://");
	string protocol = "";
	if (index != string::npos) { 
		protocol = str.substr(0, index + 3);
		str = str.substr( index+3, str.size() );
		//cout << "BAGGIO1: " << str << endl;;
		//cout << "BAGGIO1: " << protocol << endl;;
		return protocol;
	}
	else {
//		cout << "BAGGIO else"<< endl;
		return "http://";
	}
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
		return "http://";
	}
}

inline void URLNormalizer::addTrailing (string &str) {
	try{
	if(str[str.size() - 1] !=  '/')
		str = str + "/";
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}

inline void URLNormalizer::removeTrailing (string &str) {
	try{
	if(str[str.size() - 1] ==  '/')
		str = str.substr(0, str.size() - 1);
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}

/**
 * OBS: s� remove o diret�rio se ele for a �ltima coisa que aparece na string
 * ex: www.google.com/index.html => www.google.com/
 *     www.google.com/index.html?a=3 => www.google.com/index.html?a=3/
 */
inline void URLNormalizer::removeDirectoryIndexes(std::string & str) {
	for (uint i = 0; i < defaultDirectoryIndexes.size(); i++) {
		string defaultIndex = defaultDirectoryIndexes[i];
		string strEnd = "";
		if(str.find(defaultIndex) != string::npos){
			try{
				str = str.substr(0, str.size()-defaultIndex.size());
			}catch(...){}
			break;
		}
		if (str == defaultIndex.substr(1, defaultIndex.size()-1)) {
			str = "";
			break;
		}
	}
}


inline void URLNormalizer::capitalizeEscapeSequences(std::string & str) {
	try{
	for (uint i = 0; i < str.size(); i++) {
		if(str[i] == '%') 
			if (i < str.size()-2) {
				str[i+1] = toupper(str[i+1]);
				str[i+2] = toupper(str[i+2]);;
			}
	}
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}



inline void URLNormalizer::removeFragmentAndQuestionMark(std::string & str) {
	try{
	if (str.find("#") != string::npos)
		str = str.replace(str.find("#"), str.size(), "", 0, 0); // remove tudo depois de #
	if (str.find("?") != string::npos)
		str = str.replace(str.find("?"), str.size(), "", 0, 0); // remove tudo depois de ?
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}


inline void URLNormalizer::removeDefaultPort(std::string & str) {
	try{
	string strEnd = str.substr(str.size() - 3 );
	if (strEnd.find(":80") != string::npos) 
		str.erase(str.size() - 3 );
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}


inline void URLNormalizer::removeDotSegments(std::string & str) {
	try{
	string aux = "";
	while (str != "") {
		//cout << "inicio do while str: " << str << endl;
		//cout << "inicio do while aux: " << aux << endl;
		if (str.find("./") == string::npos) {
			aux = str;
			break;
		}
		if (str.find("../") == 0) {
//			cout << "1" << endl;
			str = str.substr(3, str.size());
		}
		else if (str.find("./") == 0) {
//			cout << "2" << endl;
			str = str.substr(2, str.size());
		}
		else if (str.find("/./") == 0) {
//			cout << "3" << endl;
			str = str.substr(2, str.size());
		}
		else if (str == "/.") {
//			cout << "4" << endl;
			str = str.substr(1, str.size());
			str[0] = '/';
		}
		
		//Condi��es de volta de diret�rio
		else if (str.find("/../") == 0) {
//			cout << "5" << endl;
			str = str.substr(3, str.size());
			sobeDiretorio (aux);
		}
		else if (str == "/..") {
//			cout << "6" << endl;
			str = str.substr(2, str.size());
			str[0] = '/';
			sobeDiretorio (aux);
		}
		else if (str == "." || str == ".." ) {
//			cout << "7" << endl;
			str = "";
		}
		else {
//			cout << "8" << endl;
			
			bool barraNoComeco = false;
			if (str == "/") 
				str = "";
			uint slashIndex = str.find("/");
			// se str come�a com "/", procurar a segunda "/"
			if (slashIndex == 0)  {
//				cout << "8.1 " << str << endl;
				slashIndex = (str.substr(1,str.size())).find("/") + 1;
				barraNoComeco = true;
			}
			
			//Se encontrou a "/" sem ser na posi��o inicial
			if (slashIndex != string::npos) {
//				cout << "8.2" << endl;
				//if (barraNoComeco) {
					//cout << "8.2.1" << endl;
					//aux += str.substr(1, slashIndex);
				//}
				//else {
				//	cout << "8.2.2" << endl;
					aux += str.substr(0, slashIndex);
				//}
				str  = str.substr(slashIndex, str.size());
			}
			else{
//				cout << "8.3" << endl;
				aux += str;
				str = "";
			}
		}
	}
	str = aux;
	}catch(...){
		// cout << "Baggio estragando a brincadeira... " << endl;
	}
}


inline void URLNormalizer::sobeDiretorio(std::string & str) {
	try{
	if (str == "")
		return;
	uint slashIndex = str.rfind("/");
	if (slashIndex == string::npos)
		str = "";
	else {
		str = str.substr(0, slashIndex);
	}
	}catch(...){}
}

void URLNormalizer::trim(string &str) {
    try{
//    cout << "antes trim: " << str << endl;
    string forbidden = " \t\r";
    while (str.find_last_of(forbidden) == str.size()-1 && str.size() > 0) {
        str.erase(str.size()-1);
//        cout << "inicio trim:  " << str << endl;
    }
    while (str.find_first_of(forbidden) == 0 && str.size() > 0) {
        str.erase(0,1);
//        cout << "meio trim:  " << str << endl;
    }
//    cout << "fim trim: " << str << endl;
    }catch(...){
        cout << "MC cagou o pau no URLNormalizer " << endl;
    }
}

void URLNormalizer::removeEnters(string & str){
	
	
	
	//Tentativa 1:
	string temp = "";
	temp.reserve(str.size());
	uint lastIndex = 0;
	string delimiters = " \t\n\r";

	lastIndex = str.find_first_not_of(delimiters);
	
	if (lastIndex == string::npos) {
		str = "";
		return;
	}
	
	uint firstThing = str.find_first_of(delimiters, lastIndex);
	
	while (firstThing != string::npos) {
		if (firstThing != lastIndex) {
			temp += str.substr (lastIndex, firstThing - lastIndex) + " ";
			lastIndex = firstThing + 1;
			if (lastIndex >= str.size())
				break;
		}
		else {
			lastIndex = firstThing + 1;
		}
		firstThing = str.find_first_of(delimiters, lastIndex);

	}
//	cout << lastIndex << " " << str.size() << endl;
	if (lastIndex < str.size())
		temp += str.substr(lastIndex, str.size() - lastIndex);
	
	lastIndex = temp.size() - 1;
	if (temp[lastIndex] == ' ')
		str = temp.substr(0, temp.size() - 1);
	else
		str = temp;
	
}
